home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / Libraries / Sherlock 2.0 / DevLibSrc / Mac DevLib / mac_gui.c < prev    next >
Text File  |  1995-11-03  |  40KB  |  1,769 lines

  1. /*
  2.     devlib: Macintosh GUI routines that handle windows, dialogs and menus.
  3.  
  4.     Note: The w_arg_dialog routine gets Sherlock arguments,
  5.     and depends on resource numbers for the Sherlock argument dialog.
  6.  
  7.     We want the log window to be asynchronous, i.e., we want to
  8.     send output to it at any time, even if it is not active and even if
  9.     parts of it are covered by other windows.
  10.     Writing is done immediately, without waiting for an update event.
  11.     This keeps the log window as current as possible.
  12.  
  13.     No TextEdit routines are used so as to maximize speed.
  14.     Scrolling the window is not supported.
  15.  
  16.     Except as noted, Sherlock macros may be used anywhere in this file.
  17.  
  18.     source:     mac_gui.c
  19.     started:
  20.         October 26, 1995
  21.             Changes made to support new Universal Headers.
  22.         November 4, 1993.
  23. */
  24.  
  25. /*    Version:
  26.  
  27.     Septermber 25, 1995.
  28.         Changes made for CodeWarrior.
  29.             #define Boolean int
  30.     April 13,1994.
  31.         Localized variables and converted to new-style function headers.
  32.     January 7, 1994.
  33.         Removed #include of sherlock header file.
  34.         Renamed several routines.
  35.         w_std_file_dialog and w_arg_dialog were made local to this file.
  36. */
  37.  
  38. /*    Includes. */
  39.  
  40. /* Macintosh includes. */
  41. #include <Controls.h>
  42. #include <Desk.h>
  43. #include <Dialogs.h>
  44. #include <Errors.h>
  45. #include <Events.h>
  46. #include <Files.h>
  47. #include <Fonts.h>
  48. #include <OSEvents.h>
  49. #include <OSUtils.h>
  50. #include <Quickdraw.h>
  51. #include <Memory.h>
  52. #include <Menus.h>
  53. #include <Packages.h>
  54. #include <Resources.h>
  55. #include <SegLoad.h>
  56. #include <ToolUtils.h>
  57. #include <Windows.h>
  58.  
  59. #include <LIBlib.h>
  60. #include <LIBlog.h>
  61. #include <mac_gui.h>
  62.  
  63. #ifdef __MWERKS__
  64.     #define Boolean int
  65.     #define CtoPstr c2pstr
  66.     #define PtoCstr p2cstr
  67.     #include <Strings.h>
  68.     #include <StandardFile.h>
  69. #endif
  70.  
  71. /* Make sure we call the REAL Macintosh ToolBox routines in this file. */
  72. #undef DrawMenuBar
  73. #undef GetNextEvent
  74. #undef MenuSelect
  75. #undef WaitNextEvent
  76.  
  77. #include <ctype.h>
  78. #include <stdlib.h>
  79. #include <stdio.h>
  80. #include <string.h>
  81.  
  82. #ifdef THINK_C
  83.     #include <pascal.h>
  84. #else
  85.     #include <Strings.h>    /* MPW only */
  86. #endif
  87.  
  88. #ifdef THINK_C
  89.     // From <LoMem.h>:  Warning: can't be used on a Power Mac.
  90.     // #include <LoMem.h>
  91.  
  92.     #define    Declare_LoMem(type, name, address)    type (name) : (address)
  93.     Declare_LoMem(THz, ApplZone, 0x2AA);
  94. #endif
  95.  
  96. /*    About hidden and explicit entry points.
  97.  
  98.     Several Toolbox routines are redefined via macros in sl.h to call
  99.     "hidden entry point" functions in this module.  The macros that
  100.     redefine the Toolbox routines must not be active in this file!!
  101.  
  102.     Toolbox Function            Hidden Entry Point Function
  103.  
  104.         DrawMenuBar                w_drawMenuBar
  105.         GetNextEvent            w_event
  106.         MenuSelect                w_menuSelect
  107.         WaitNextEvent            w_event
  108.  
  109.     Explicit entry points        Called by
  110.  
  111.         w_applEvent                directly
  112.         w_mac_init                directly
  113.         w_arg_dialog            directly
  114.         w_std_file_dialog        directly
  115.         w_init                    from all other entry points
  116.         slw_write                log_cout
  117.         slw_update                directly
  118.  
  119.     Coding conventions:
  120.  
  121.     Each entry point, hidden or not, must preserve the GrafPort
  122.     or the application will crash.
  123.     Local routines need not preserve the GrafPort because the entry points do so.
  124.  
  125.     Each entry point (or its continuation in the case of sl_wCout) calls
  126.     w_init if necessary before using any variable defined in this file.
  127.     This is a defensive measure so the code in this file will not crash
  128.     if the application calls one of the hidden entry points before calling
  129.     SL_INIT.
  130.  
  131.     WARNING:  SetPort(w_wp) must be done *after* calling w_init
  132.     because w_init itself preserves the GrafPort.
  133. */
  134.  
  135. /*    Constants.
  136.  
  137.     Change these constants if you change the resource ID's in the dialog
  138.     named "Sherlock Dialog" in the file called Sherlock Resources.
  139. */
  140. #define SHERLOCK_DIALOG_ID    206    /* Resource ID of dialog. */
  141. #define OK_ITEM               1    /* Dialog Item Numbers... */
  142. #define CANCEL_ITEM            2
  143. #define TO_DISK_FILE_ITEM    3
  144. #define SHERLOCK_ARGS_ITEM    5
  145.  
  146. /*
  147.     Constants for menu handling.
  148.     The values of these items correspond to the order of code in w_drawMenuBar.
  149.  
  150.     MBarHeight is a low memory global, whose value is usually 20.
  151. */
  152. #ifndef THINK_C /* Think C defines MBarHeight to be a low-memory global. */
  153.     #define MBarHeight 20
  154. #endif
  155.  
  156. #define APPLE_MENU_ID    128        /* Resource ID's for menus... */
  157. #define FILE_MENU_ID    129
  158. #define EDIT_MENU_ID    130
  159. #define QUIT_ITEM         1        /* File menu. */
  160.  
  161. #define W_OPTIONS_ITEM    1        /* Sherlock menu... */
  162.                 /* Item 2 is a dimmed line */
  163. #define W_STATS_ITEM    3
  164. #define W_STATS2_ITEM    4
  165. #define W_CLEAR_ITEM    5
  166.                 /* Item 6 is a dimmed line */
  167. #define W_FILE_ITEM    7
  168. #define W_WINDOW_ITEM    8
  169.                 /* Item 9 is a dimmed line */
  170. #define W_STACK_ITEM    10
  171. #define W_DUMP_ITEM        11
  172. #define W_DUMP2_ITEM    12
  173. #define W_DUMP3_ITEM    13
  174.  
  175. /*    Prototypes of internal routines. */
  176.  
  177. static void        w_abort            (int beeps);
  178. static void     w_arg_dialog
  179.     (char * on_string, char * off_string,
  180.     char * fileNamePrompt, char * defaultFileName);
  181.  
  182. static void        w_activate        (Boolean active_flag);
  183. static Boolean    w_command        (long where);
  184. static Boolean    w_commandStd    (long where);
  185. static void        w_content        (void);
  186. static void        w_drag            (Point global_pt);
  187. static void        w_goAway        (Point global_pt);
  188. static void        w_grow            (Point global_pt);
  189. static void        w_hide            (void);
  190. static void        w_hiliteButton    (DialogPtr dp);
  191. static void     w_init            (Boolean openFlag, char * windowName);
  192. static Boolean    w_key            (EventRecord * event);
  193. static void        w_line_insert    (char * buffer, int count);
  194. static void        w_line_out        (void);
  195. static void        w_line_update    (void);
  196. static void        w_pStr            (char * s);
  197.  
  198. static Boolean    w_rawDialog
  199.     (short * vRefNum, char * fileName, int max_fileName,
  200.     char * fileNamePrompt, char * defaultFileName);
  201.  
  202. static void        w_scrollWindow    (void);
  203. static int        w_std_file_dialog
  204.     (short * vRefNum, char * fileName, int max_fileName,
  205.     char * fileNamePrompt, char * defaultFileName);
  206.  
  207. static void        w_setupWindow    (void);
  208. static void        w_show            (void);
  209. static void        w_zoom            (Point global_pt, int zoomCode);
  210.  
  211. /*    Local vars. */
  212.  
  213.     /* w_mac_init: Output control flags. */
  214.  
  215. static Boolean    w_windowFlag = TRUE;        /* TRUE: output to window. */
  216. static void (*w_aboutCallBack)(void) = 0L;    /* "about" callback routine. */
  217. static void (*w_eventCallBack)(void) = 0L;    /* event callback routine. */
  218. static void (*w_dumpCallBack)(void)     = 0L;    /* user dump callback routine. */
  219. static void (*w_dump2CallBack)(void) = 0L;    /* user dump callback routine. */
  220. static void (*w_dump3CallBack)(void) = 0L;    /* user dump callback routine. */
  221.  
  222.     /* w_mac_init: Menu initialization values. */
  223.  
  224. static Boolean w_aboutFlag   = FALSE;    /* TRUE: add about item. */
  225. static Boolean w_stdMenuFlag = FALSE;    /* TRUE: add standard menus. */
  226. static Boolean w_slMenuFlag  = FALSE;    /* TRUE: add sherlock menu. */
  227. static pstring w_aboutTitle  = "\p";    /* Name of "about" menu item. */
  228. static pstring w_userItem1   = "\p";    /* Title of first user item. */
  229. static pstring w_userItem2   = "\p";    /* Title of second user item. */
  230. static pstring w_userItem3   = "\p";    /* Title of third user item. */
  231.  
  232.     /* Internal state flags. */
  233.  
  234. static int        w_eventSkipCount = 0;        /* w_applEvent skip count. */
  235. static Boolean    w_toolBoxFlag    = FALSE;    /* TRUE: Mac ToolBox inited. */
  236. static Boolean    w_wInitFlag        = FALSE;    /* TRUE: w_init inited. */
  237. static Boolean    w_MBarFlag        = FALSE;    /* TRUE: menu bar inited. */
  238. static Boolean    w_activeFlag    = FALSE;    /* TRUE: window active. */
  239. static Boolean    w_showFlag        = TRUE;        /* TRUE: window is showing. */
  240.  
  241.     /* The circular line buffer. */
  242. /*
  243.     This buffer hold the last MAX_SLOTS lines and is used to
  244.     refresh the log window during update events.
  245.  
  246.     The code will work regardless of the value of MAX_SLOTS, but
  247.     MAX_SLOTS should be chosen so that it is greater than the number
  248.     of lines in the log window.
  249.  
  250.     All entries in the buffer are MAX_LINE_CHARS long, which makes
  251.     replacing one line by another easy.
  252. */
  253.  
  254. #define MAX_SLOTS 30
  255. #define MAX_LINE_CHARS 120
  256. #define MAX_WBUF (MAX_SLOTS * MAX_LINE_CHARS)
  257.  
  258. static char    * w_wBuf    = NULL;                /* Character buffer. */
  259. static int * w_wCount    = NULL;                /* Line counts. */
  260. static int    w_wSlot        = -1;                 /* Current wBuf slot. */
  261. static int    w_wIndex    = -MAX_LINE_CHARS;    /* Current wBuf index. */
  262. static int    w_wLines    = 0;                /* Current line count. */
  263. static int    w_wMaxLines    = 0;                /* Window size in lines. */
  264.  
  265.     /* Descriptions of the current font and screen layout. */
  266.  
  267. #define LEFT_OFFSET        4    /* Left Margin. */
  268. #define TOP_CLIP        4    /* Should be >= 0. */
  269. #define RIGHT_CLIP        4    /* Should be at least 1. */
  270. #define BOTTOM_CLIP        4    /* Should be at least 1. */
  271. #define SBarWidth        15    /* Width of scroll bars. */
  272. #define EXTRA_LEADING    1    /* Can be zero. */
  273.  
  274. static int    w_height = 0;            /* Distance above baseline. */
  275. static int    w_dy = 0;                /* Distance between lines. */
  276. static int    w_y0 = 0;                /* Offset of first line. */
  277. static int    w_maxRow = MAX_SLOTS;    /* Writable verticle pixels. */
  278. static int    w_curRow = 0;            /* Current row number. */
  279. static int    w_MBarHeight = 20;        /* Height of menu bar. */
  280.  
  281.     /* Buffers used to accumulate Sherlock arguments. */
  282.  
  283. #define    MAX_ARGS    50
  284. #define MAX_COMMAND 500
  285.  
  286. static    int    w_argc    = 1;
  287. static    char* w_argv[MAX_ARGS];                    /* Command line buffers. */
  288. static    unsigned char w_comBuf[MAX_COMMAND];
  289.  
  290.     /* Window and menu vars. */
  291.  
  292. static WindowPtr w_wp = 0L;
  293.  
  294. static Rect w_boundsRect;
  295. static Rect    w_clipRect;
  296. static Rect w_dragRect;
  297. static Rect    w_growRect;
  298.  
  299. static MenuHandle    w_menuH            = 0L;
  300. static MenuHandle    w_appleMenuH    = 0L;
  301. static MenuHandle    w_fileMenuH        = 0L;
  302. static MenuHandle    w_editMenuH        = 0L;
  303. static int             w_sherlockID    = -1;
  304.  
  305. /*    w_abort
  306.     This routine is called if the log window can't be initialized.
  307.     Assume nothing is available that must be initialized.
  308. */
  309. static void
  310. w_abort(int beeps)
  311. {
  312.     #if defined(THINK_C) || defined(__MWERKS__)
  313.         int i;
  314.         for (i = 0; i < beeps; i++) {
  315.             SysBeep(20);
  316.         }
  317.         abort();
  318.     #else
  319.         abort();
  320.     #endif
  321. }
  322.  
  323. /*    w_activate: handle an activate event.
  324.     Set w_activeFlag as appropriate.
  325.     Events are handled in the log window only if w_activeFlag is TRUE.
  326. */
  327. static void
  328. w_activate(Boolean active_flag)
  329. {
  330.     /* Remember the state of the log window. */
  331.     w_activeFlag = active_flag;
  332.  
  333.     /* Never wait for an update event. */
  334.     if (active_flag) {
  335.         slw_update();
  336.     }
  337. }
  338.  
  339. /*    w_applEvent: an explicit entry point.
  340.  
  341.     This routine provides a minimal event-loop for an application.
  342.     Return FALSE if the application should quit.
  343.  
  344.     WARNING: Do not call this routine if
  345.     o Your program uses the stdout output stream (putchar, printf, etc.)
  346.         -- or --
  347.     o Your program has another event loop.
  348. */
  349. Boolean
  350. w_applEvent(int eventSkipCount)
  351. {
  352.     GrafPtr        oldPort;
  353.     EventRecord    applEvent;
  354.     Boolean        return_value;
  355.  
  356.     GetPort(&oldPort);
  357.  
  358.     /* Initialize the log window if required. */
  359.     if (!w_wInitFlag) {
  360.         w_init(FALSE, "log");
  361.     }
  362.  
  363.     SetPort(w_wp);
  364.  
  365.     /* Execute this routine only once every eventSkipCount calls. */
  366.     if (eventSkipCount > 0 && w_eventSkipCount++ < eventSkipCount) {
  367.         goto true_ret;
  368.     }
  369.     else {
  370.         /* Start counting up again. */
  371.         w_eventSkipCount = 0;
  372.     }
  373.  
  374.     /* Get the event using w_event. Return TRUE if there is none. */
  375.     /* Calls to TEIdle and SystemTask are handled by w_event. */
  376.     if (!w_event(everyEvent, &applEvent, 0L, NULL, FALSE)) {
  377.         goto true_ret;
  378.     }
  379.  
  380.     if (applEvent.what == nullEvent) {
  381.         goto true_ret;
  382.     }
  383.  
  384.     switch (applEvent.what) {
  385.  
  386.     case mouseDown:
  387.     {
  388.         WindowPtr applWindow;
  389.  
  390.         switch (FindWindow(applEvent.where, &applWindow)) {
  391.  
  392.         case inMenuBar:
  393.             if (w_MBarFlag && w_stdMenuFlag) {
  394.                 return_value = w_commandStd(w_menuSelect(applEvent.where));
  395.                 goto value_ret;
  396.             }
  397.             else {
  398.                 /* Menu bar not installed.  Ignore mouseDown events. */
  399.                 goto true_ret;
  400.             }
  401.  
  402.         case inSysWindow:
  403.             SystemClick(&applEvent, applWindow );
  404.             goto true_ret;
  405.  
  406.         default:
  407.             goto true_ret;
  408.         }
  409.     }
  410.  
  411.     case keyDown: case autoKey:
  412.     {
  413.         /* Do nothing if the menu bar has not been installed. */
  414.         char c = applEvent.message & charCodeMask;
  415.         if (w_MBarFlag && w_stdMenuFlag && (applEvent.modifiers & cmdKey) != 0) {
  416.             return_value = w_commandStd(MenuKey(c));
  417.             goto value_ret;
  418.         }
  419.         else {
  420.             goto true_ret;
  421.         }
  422.     }
  423.  
  424.     case activateEvt: case updateEvt: default:
  425.         goto true_ret;
  426.  
  427.     }
  428.  
  429. value_ret:
  430.     SetPort(oldPort);
  431.     return return_value;
  432.  
  433. true_ret:
  434.     SetPort(oldPort);
  435.     return TRUE;
  436.  
  437. }
  438.  
  439. /*    w_arg_dialog: an explicit entry point.
  440.     Prompt the user for arguments and file name.
  441. */
  442. static void
  443. w_arg_dialog (
  444.     char * on_string,
  445.     char * off_string,
  446.     char * fileNamePrompt,
  447.     char * defaultFileName)
  448. {
  449.     Boolean    fileFlag;
  450.     GrafPtr    oldPort;
  451.     short    vRefNum;
  452.     char    fileName[MAX_LOG_FILE_NAME];
  453.  
  454.     GetPort(&oldPort);
  455.  
  456.     /* Initialize the log window if required. */
  457.     if (!w_wInitFlag) {
  458.         w_init(FALSE, "log");
  459.     }
  460.  
  461.     SetPort(w_wp);
  462.  
  463.     /* Get arguments, including w_comBuf. */
  464.     fileFlag = w_rawDialog(&vRefNum, fileName, MAX_LOG_FILE_NAME,
  465.                     fileNamePrompt, defaultFileName);
  466.  
  467.     /* Parse the arguments entered from the dialog box. */
  468.     {
  469.         char    c;
  470.         char *    cp = (char *) &w_comBuf[0];
  471.         w_argc = 1;
  472.         while (w_argc < MAX_ARGS) {
  473.     
  474.             while (isspace(*cp)) {
  475.                 cp++;
  476.             }
  477.             if ( !*cp ) {
  478.                 break;
  479.             }
  480.     
  481.             /* Point w_argv[] at the start of the argument. */
  482.             w_argv[w_argc++] = cp++;
  483.     
  484.             /* Scan past the argument and terminate the argument. */
  485.             while (*cp && !isspace(*cp)) {
  486.                 cp++;
  487.             }
  488.             c = *cp;
  489.             *cp++ = '\0';
  490.             if (!c) {
  491.                 break;
  492.             }
  493.         }
  494.     }
  495.  
  496.     /* Initialize the Sherlock variables. */
  497.     #ifdef SHERLOCK /* 12/13/93 */
  498.         sl_parse(&w_argc, w_argv, on_string, off_string);
  499.     #endif
  500.  
  501.     /* Open the requested file, if any. */
  502.     if (fileFlag && fileName[0] != '\0') {
  503.         log_open_vRefNum(vRefNum, fileName);
  504.     }
  505.  
  506.     SetPort(oldPort);
  507. }
  508.  
  509. /*    w_command: handle Sherlock menu commands. Called from w_event().
  510.  
  511.     Return FALSE if the user must take further action.
  512. */
  513. static Boolean
  514. w_command(long where)
  515. {
  516.     int    item = LoWord(where);
  517.     int    menu = HiWord(where);
  518.  
  519.     /* Return false if the Sherlock menu has not bee installed. */
  520.     if (w_sherlockID == -1 || menu != w_sherlockID) {
  521.         return FALSE;
  522.     }
  523.  
  524.     switch(item) {
  525.  
  526.         /* Item cases. */
  527.  
  528.     case W_OPTIONS_ITEM:
  529.         /* Use simple ++ and -- for prefix here. */
  530.         w_arg_dialog("++", "--", lib_log_file_prompt, lib_log_file_name);
  531.         break;
  532.  
  533.     case W_STATS_ITEM:
  534.         #ifdef SHERLOCK /* 12/13/93 */
  535.             sl_edump();
  536.         #endif
  537.         break;
  538.  
  539.     case W_STATS2_ITEM:
  540.         #ifdef SHERLOCK /* 12/13/93 */
  541.             sl_dump();
  542.         #endif
  543.         break;
  544.  
  545.     case W_CLEAR_ITEM:
  546.         #ifdef SHERLOCK /* 12/13/93 */
  547.             sl_clear();
  548.         #endif
  549.         break;
  550.  
  551.     case W_FILE_ITEM:
  552.         if (log_isopen()) {
  553.             log_close();
  554.         }
  555.         else {
  556.             short vRefNum;
  557.             char  fileName[MAX_LOG_FILE_NAME];
  558.             if(w_std_file_dialog(&vRefNum, fileName, MAX_LOG_FILE_NAME,
  559.                 "Sherlock Tracing File...", "sl_trace")
  560.             ) {
  561.                 log_open_vRefNum(vRefNum, fileName);
  562.             }
  563.         }
  564.         break;
  565.  
  566.     case W_WINDOW_ITEM:
  567.  
  568.         if (w_showFlag) {
  569.             w_hide();
  570.         }
  571.         else {
  572.             w_show();
  573.         }
  574.         break;
  575.  
  576.     case W_STACK_ITEM:
  577.  
  578.         /* Stack walk-back */
  579.         #ifdef SHERLOCK /* 12/13/93 */
  580.             sl_dumpstk();
  581.         #endif
  582.         break;
  583.  
  584.     case W_DUMP_ITEM:
  585.  
  586.         /* Execute the user dump routine. */
  587.         if (w_dumpCallBack != 0L) {
  588.             (*w_dumpCallBack)();
  589.         }
  590.         break;
  591.  
  592.     case W_DUMP2_ITEM:
  593.  
  594.         /* Execute the user dump routine. */
  595.         if (w_dump2CallBack != 0L) {
  596.             (*w_dump2CallBack)();
  597.         }
  598.         break;
  599.  
  600.     case W_DUMP3_ITEM:
  601.  
  602.         /* Execute the user dump routine. */
  603.         if (w_dump3CallBack != 0L) {
  604.             (*w_dump3CallBack)();
  605.         }
  606.         break;
  607.  
  608.     default: break;
  609.  
  610.     }
  611.  
  612.     HiliteMenu(0);
  613.     return TRUE;
  614. }
  615.  
  616. /*    w_commandStd: handle standard menu commands.  Called from w_applEvent().
  617.     Return FALSE if the application should quit.
  618. */
  619. static Boolean
  620. w_commandStd(long where)
  621. {
  622.     int item = LoWord(where);
  623.     int menu = HiWord(where);
  624.  
  625.     /* Do nothing if the standard menu has not been installed. */
  626.     if (!w_stdMenuFlag || !w_MBarFlag) {
  627.         return TRUE;
  628.     }
  629.     
  630.     switch(menu) {
  631.  
  632.     case APPLE_MENU_ID:
  633.         if (item == 1 && w_aboutFlag) {
  634.             if (w_aboutCallBack != 0L) {
  635.                 /* Execute the user's dialog routine. */
  636.                 (*w_aboutCallBack)();
  637.             }
  638.             HiliteMenu(0);
  639.             return TRUE;
  640.         }
  641.         else {
  642.             /* Enable the edit menu. */
  643.             Str255    DAName;
  644.             EnableItem(w_editMenuH, 0);
  645.             GetItem(w_appleMenuH, item, DAName);
  646.             OpenDeskAcc(DAName);
  647.             DisableItem(w_editMenuH, 0);
  648.             HiliteMenu(0);
  649.             return TRUE;
  650.         }
  651.  
  652.     case FILE_MENU_ID:
  653.         HiliteMenu(0);
  654.         if (item == QUIT_ITEM) {
  655.             return FALSE;
  656.         }
  657.         else {
  658.             return TRUE;
  659.         }
  660.  
  661.     default:
  662.         HiliteMenu(0);
  663.         return TRUE;
  664.  
  665.     }
  666. }
  667.  
  668. /*    w_content: handle a mouse down event in the content region of the log window. */
  669. static void
  670. w_content(void)
  671. {
  672.     if (FrontWindow() != w_wp) {
  673.         SelectWindow(w_wp);
  674.         ShowCursor();
  675.     }
  676. }
  677.  
  678. /*    w_drag: Handle a mouse down event in the drag region of the log window. */
  679. static void
  680. w_drag(Point global_pt)
  681. {
  682.     DragWindow(w_wp, global_pt, &w_dragRect );
  683. }
  684.  
  685. /*    w_drawMenuBar: a hidden entry point called by the DrawMenuBar macro.
  686.  
  687.     This is also called by sl_applMenuInit().
  688.     Install the Sherlock menu as the last menu and
  689.     call the DrawMenuBar Toolbox routine.
  690. */
  691. void
  692. w_drawMenuBar(void)
  693. {
  694.     GrafPtr oldPort;
  695.  
  696.     /* Just call the Macintosh ToolBox DrawMenuBar if we have been inited. */
  697.     if (w_MBarFlag) {
  698.         DrawMenuBar();
  699.         return;
  700.     }
  701.  
  702.     /* Save */
  703.     GetPort(&oldPort);
  704.  
  705.     /* Initialize the log window if required. */
  706.     if (!w_wInitFlag) {
  707.         w_init(FALSE, "log");
  708.     }
  709.  
  710.     SetPort(w_wp);
  711.  
  712.     if (w_stdMenuFlag) {
  713.  
  714.         /* Install the apple, file, and edit menus. */
  715.  
  716.         /* Install the apple menu. */
  717.         w_appleMenuH = NewMenu(APPLE_MENU_ID, "\p\024");
  718.  
  719.         /* Install the about item if present. */
  720.         if (w_aboutFlag && w_aboutTitle != 0L && w_aboutTitle[0] != 0) {
  721.             AppendMenu(w_appleMenuH, w_aboutTitle);
  722.         }
  723.  
  724.         /* Install the list of Desk Accessories in the apple menu. */
  725.         AddResMenu(w_appleMenuH, 'DRVR' );
  726.         InsertMenu(w_appleMenuH, 0);
  727.  
  728.         /* Insert a file menu containing only quit. */
  729.         w_fileMenuH = NewMenu(FILE_MENU_ID, "\pFile");
  730.         AppendMenu(w_fileMenuH, "\pQuit/Q");
  731.         InsertMenu(w_fileMenuH, 0);
  732.  
  733.         /* Insert the standard, dimmed edit menu. */
  734.         w_editMenuH = NewMenu(EDIT_MENU_ID, "\pEdit");
  735.         AppendMenu(w_editMenuH, "\pUndo/Z");
  736.         AppendMenu(w_editMenuH, "\p(-");
  737.         AppendMenu(w_editMenuH, "\pCut/X");
  738.         AppendMenu(w_editMenuH, "\pCopy/C");
  739.         AppendMenu(w_editMenuH, "\pPaste/V");
  740.         InsertMenu(w_editMenuH, 0);
  741.  
  742.         /* Dim the entire edit menu. */
  743.         DisableItem(w_editMenuH, 0);
  744.  
  745.         /* Make sure we never mess with the menus again. */
  746.         w_MBarFlag = TRUE;
  747.     }
  748.  
  749.     if (w_slMenuFlag) {
  750.  
  751.         /* Install the Sherlock menu. */
  752.  
  753.         /* Initialize the Sherlock menu information. */
  754.         int i = 0;
  755.         for (i = 128; i < 200; i++) {
  756.             if (GetMHandle(i) == 0L) {
  757.                 w_sherlockID = i;
  758.                 break;
  759.             }
  760.         }
  761.  
  762.         /* Enter items into the Sherlock menu. */
  763.         w_menuH = NewMenu(w_sherlockID, "\pSherlock");
  764.         AppendMenu(w_menuH, "\pOptions...");
  765.         AppendMenu(w_menuH, "\p(-");
  766.         AppendMenu(w_menuH, "\pEnabled Stats");
  767.         AppendMenu(w_menuH, "\pAll Stats");
  768.         AppendMenu(w_menuH, "\pClear Stats");
  769.         AppendMenu(w_menuH, "\p(-");
  770.         if (log_isopen()) {
  771.             AppendMenu(w_menuH, "\pClose File");
  772.         }
  773.         else {
  774.             AppendMenu(w_menuH, "\pOpen File");
  775.         }
  776.         if (w_showFlag) {
  777.             AppendMenu(w_menuH, "\pClose Window");
  778.         }
  779.         else {
  780.             AppendMenu(w_menuH, "\pOpen Window");
  781.         }
  782.         AppendMenu(w_menuH, "\p(-");
  783.         AppendMenu(w_menuH, "\pCall Stack");
  784.  
  785.         /* Install call back routines. */
  786.         if (w_dumpCallBack != 0L) {
  787.             AppendMenu(w_menuH, w_userItem1);
  788.  
  789.             if (w_dump2CallBack != 0L) {
  790.                 AppendMenu(w_menuH, w_userItem2);
  791.  
  792.                 if (w_dump3CallBack != 0L) {
  793.                     AppendMenu(w_menuH, w_userItem3);
  794.                 }
  795.             }
  796.         }
  797.  
  798.         InsertMenu(w_menuH, 0);
  799.  
  800.         /* Make sure we never mess with the menus again. */
  801.         w_MBarFlag = TRUE;
  802.     }
  803.  
  804.     /* Call the real Toolbox routine. */
  805.     DrawMenuBar();
  806.  
  807.     /* Restore */
  808.     SetPort(oldPort);
  809. }
  810.  
  811. /*    w_event: a hidden entry point called by GetNextEvent and WaitNextEvent macros.
  812.  
  813.     The WaitNextEvent macro sets wait_flag to TRUE.
  814.  
  815.     Call the GetNextEvent() or the WaitNextEvent Toolbox routine,
  816.     handle all events that pertain to the log window,
  817.     and pass all other events on to the caller.
  818.  
  819.     Return TRUE if the event requires further action.
  820. */
  821. Boolean
  822. w_event(
  823.     int user_mask,
  824.     EventRecord * event,
  825.     long sleep,
  826.     RgnHandle mouseRgn,
  827.     Boolean wait_flag)
  828. {
  829.     GrafPtr        oldPort;
  830.     WindowPtr    wp = NULL;
  831.     Boolean        defaultReturn;
  832.  
  833.     /* Save */
  834.     GetPort(&oldPort);
  835.  
  836.     /* Initialize the log window if required. */
  837.     if (!w_wInitFlag) {
  838.         w_init(FALSE, "log");
  839.     }
  840.  
  841.     SetPort(w_wp);
  842.  
  843.     /* Get the next event, if any. */
  844.     /* Both these calls update the caller's event record. */
  845.     if (wait_flag) {
  846.         defaultReturn = WaitNextEvent(user_mask, event, sleep, mouseRgn);
  847.     }
  848.     else {
  849.         defaultReturn = GetNextEvent(user_mask, event);
  850.     }
  851.  
  852.     if (event->what == nullEvent) {
  853.         goto true_ret;
  854.     }
  855.  
  856.     switch (event -> what) {
  857.  
  858.     case keyDown: case autoKey:
  859.  
  860.         /* Handle keypressed events only if log window is active. */
  861.         if (!w_activeFlag) {
  862.             goto true_ret;
  863.         }
  864.         else if (w_key(event)) {
  865.             goto false_ret;
  866.         }
  867.         else {
  868.             goto true_ret;
  869.         }
  870.  
  871.     case mouseUp: case nullEvent:
  872.         /* Let user handle these. */
  873.         goto true_ret;
  874.  
  875.     case activateEvt:
  876.         if ( ((WindowPtr) event -> message) != w_wp) {
  877.             goto true_ret;
  878.         }
  879.         else {
  880.             w_activate(((event -> modifiers) & activeFlag) != 0);
  881.             goto false_ret;
  882.         }
  883.  
  884.     case updateEvt:
  885.         if ( ((WindowPtr) event -> message) != w_wp) {
  886.             goto true_ret;
  887.         }
  888.         else {
  889.             slw_update();
  890.             goto false_ret;
  891.         }
  892.  
  893.     case mouseDown:
  894.     {
  895.         int window_type = FindWindow(event->where, &wp);
  896.         switch (window_type) {
  897.  
  898.         case inSysWindow:
  899.             /* User handles all desk accessories. */
  900.             goto true_ret;
  901.  
  902.         case inMenuBar:
  903.             /* w_menuSelect will handle this later. */
  904.             goto true_ret;
  905.  
  906.         case inContent:
  907.             /* Only handle log windows here. */
  908.             if (wp != w_wp) {
  909.                 goto true_ret;
  910.             }
  911.             else {
  912.                 Point local_pt = event -> where;
  913.                 GlobalToLocal(&local_pt);
  914.                 w_content( /* local_pt, event->modifiers */ );
  915.                 goto false_ret;
  916.             }
  917.  
  918.         case inDrag:
  919.             /* Only handle log windows here. */
  920.             if (wp != w_wp) {
  921.                 goto true_ret;
  922.             }
  923.             else {
  924.                 w_drag(event -> where);
  925.                 goto false_ret;
  926.             }
  927.  
  928.         case inGrow:
  929.             /* Only handle log windows here. */
  930.             if (wp != w_wp) {
  931.                 goto true_ret;
  932.             }
  933.             else {
  934.                 w_grow(event -> where);
  935.                 goto false_ret;
  936.             }
  937.  
  938.         case inGoAway:
  939.             /* Only handle log windows here. */
  940.             if (wp != w_wp) {
  941.                 goto true_ret;
  942.             }
  943.             else {
  944.                 w_goAway(event -> where);
  945.                 goto false_ret;
  946.             }
  947.  
  948.         case inZoomIn: case inZoomOut:
  949.             /* Only handle log windows here. */
  950.             if (wp != w_wp) {
  951.                 goto true_ret;
  952.             }
  953.             else {
  954.                 w_zoom(event -> where, window_type);
  955.                 goto false_ret;
  956.             }
  957.  
  958.         default: goto true_ret;
  959.  
  960.         }
  961.     } /* End mouseDown cases */
  962.  
  963.     default:
  964.         if (defaultReturn) {
  965.             goto true_ret;
  966.         }
  967.         else {
  968.             goto false_ret;
  969.         }
  970.  
  971.     } /* End event->what cases. */
  972.  
  973. true_ret:
  974.     SetPort(oldPort);
  975.     return TRUE;
  976.  
  977. false_ret:
  978.     SetPort(oldPort);
  979.     return FALSE;
  980.  
  981. }
  982.  
  983. /*    w_goAway: handle a mouse down event in the log window go away box. */
  984. static void
  985. w_goAway(Point global_pt)
  986. {
  987.     if (TrackGoAway(w_wp, global_pt)) {
  988.         w_hide();
  989.     }
  990. }
  991.  
  992. /*    w_grow: handle a mouse down event in the log window grow box. */
  993. static void
  994. w_grow(Point global_pt)
  995. {
  996.     long theResult = GrowWindow(w_wp, global_pt, &w_growRect);
  997.     if (theResult) {
  998.  
  999.         /* Resize and redraw the window. */
  1000.         SizeWindow(w_wp, LoWord(theResult), HiWord(theResult), 1);
  1001.  
  1002.         /* Set the clipping region for EraseRect and DrawGrowIcon. */
  1003.         ClipRect(&w_wp->portRect);
  1004.     
  1005.         EraseRect(&w_wp->portRect);
  1006.         DrawGrowIcon(w_wp);
  1007.     
  1008.         /* Restore the clipping region. */
  1009.         w_setupWindow();
  1010.     
  1011.         /* No update event is generated if the window becomes smaller. */
  1012.         w_line_update();
  1013.  
  1014.     }
  1015. }
  1016.  
  1017. /*    w_hide: hide the log window. */
  1018. static void
  1019. w_hide(void)
  1020. {
  1021.     HideWindow(w_wp);
  1022.     w_showFlag = FALSE;
  1023. }
  1024.  
  1025. /*    w_hiliteButton: Hilite the default button in slot 1.
  1026.  
  1027.     Do not put any Sherlock traces in this routine.
  1028. */
  1029. static void
  1030. w_hiliteButton(DialogPtr dp)
  1031. {
  1032.     Rect tempRect;
  1033.  
  1034.     {
  1035.         short    DType;
  1036.         Handle    DItem;
  1037.         GetDItem(dp, OK_ITEM, &DType, &DItem, &tempRect);
  1038.     }
  1039.  
  1040.     /* Code from Inside Macintosh I-407 (Dialog Manager.) */
  1041.     PenSize(3, 3);
  1042.     InsetRect(&tempRect, -4, -4);
  1043.     FrameRoundRect(&tempRect, 16, 16);
  1044.     PenSize(1, 1);
  1045. }
  1046.  
  1047. /*    w_init: an explicit entry point.  Called from all entry points.
  1048.  
  1049.     Initialize the log window.
  1050.  
  1051.     Do not put a Sherlock macro in this routine!!
  1052.  
  1053.     This code should be called first from w_mac_init.
  1054.     As a precaution, it is called from all entry points if needed.
  1055.  
  1056.     Beep 3 times and exits if the ToolBox has not been initialized properly.
  1057.     Beep 4 times and exits if the log window can't be created.
  1058. */
  1059. static void
  1060. w_init(Boolean openFlag, char * windowName)
  1061. {
  1062.     GrafPtr     oldPort;
  1063.  
  1064.     /* Allow the user to call this twice without effect. */
  1065.     if (w_wInitFlag) {
  1066.         return;
  1067.     }
  1068.  
  1069.     /*    Beep 3 times if the ToolBox does not appear to have been initialized.
  1070.  
  1071.         This check is not foolproof!
  1072.         We will crash if the application does not initialize the ToolBox and
  1073.         does not ask w_mac_init to initialize the ToolBox.
  1074.     */
  1075.     if (!w_toolBoxFlag) {
  1076.         SysBeep(20);
  1077.         SysBeep(20);
  1078.         SysBeep(20);
  1079.         ExitToShell();
  1080.     }
  1081.  
  1082.     GetPort(&oldPort);
  1083.  
  1084.     /* Remember the initial state of the window. */
  1085.     w_showFlag    = openFlag;
  1086.  
  1087.     /* Allocate memory for the line buffers. */
  1088.     w_wBuf        = malloc(MAX_WBUF);
  1089.     w_wCount    = malloc(MAX_SLOTS * sizeof(int));
  1090.  
  1091.     /* Create a window of the size specified. */
  1092.     SetRect(&w_boundsRect, 3, 40, 500, 230);
  1093.     CtoPstr(windowName);
  1094.     w_wp = NewWindow(NULL, &w_boundsRect, (pstring) windowName,
  1095.         openFlag,                 /* visible flag    (was TRUE)        */
  1096.         /* documentProc */ 8,    /* window definition ID.         */
  1097.         ((WindowPtr) 0L),        /* 0L: behind all: -1L in front */
  1098.         TRUE,                    /* has go-away box.                */
  1099.         0L);                    /* no refCon field.                */
  1100.     PtoCstr( (pstring) windowName);
  1101.  
  1102.     /* Beep 4 times and abort if the window could not be created. */
  1103.     if (w_wp == 0L) {
  1104.         SysBeep(20);
  1105.         SysBeep(20);
  1106.         SysBeep(20);
  1107.         SysBeep(20);
  1108.         ExitToShell();
  1109.     }
  1110.  
  1111.     SetPort(w_wp);
  1112.  
  1113.     /* Set the menu bar height based on what version of ROM we are using. */
  1114.     {
  1115.         SysEnvRec    theWorld;
  1116.  
  1117.         if (SysEnvirons(1, &theWorld) == envNotPresent) {
  1118.             /* Default to 20. */
  1119.             w_MBarHeight = 20;
  1120.         }
  1121.         else {
  1122.             /* Get value from system global. */
  1123.             w_MBarHeight = GetMBarHeight();
  1124.         }
  1125.     }
  1126.  
  1127.     /*    Set the boundsRect for w_drag().
  1128.         This only needs to be done once.
  1129.     */
  1130.     SetRect(&w_dragRect,
  1131.         4, w_MBarHeight + 4,
  1132.         qd.screenBits.bounds.right - 4, qd.screenBits.bounds.bottom - 4);
  1133.  
  1134.     /* Set the sizeRect for w_grow(). */
  1135.     SetRect(&w_growRect,
  1136.         4, w_MBarHeight + 4,
  1137.         qd.screenBits.bounds.right - 4, qd.screenBits.bounds.bottom - 4);
  1138.  
  1139.     /* Initialize the window. */
  1140.     w_setupWindow();
  1141.  
  1142.     /* Indicate that the log window system is inited. */
  1143.     w_wInitFlag = TRUE;
  1144.  
  1145.     SetPort(oldPort);
  1146. }
  1147.  
  1148. /*    w_key: handle key events when the log window is active.
  1149.     Edit command keys and normal keys are handled here.
  1150.     All other command keys are passed along to the user.
  1151.  
  1152.     Return FALSE if the user must take further action.
  1153.  
  1154.     Do not put a Sherlock macro in this routine.
  1155. */
  1156. static Boolean
  1157. w_key(EventRecord * event)
  1158. {
  1159.     char c = event -> message & charCodeMask;
  1160.     if ((event -> modifiers & cmdKey) != 0) {
  1161.         return w_command(MenuKey(c));
  1162.     }
  1163.     else {
  1164.         return FALSE;
  1165.     }
  1166. }
  1167.  
  1168. /*    w_line_insert: insert a line into the buffer, replacing the oldest line.
  1169.     Long lines are silently truncated.
  1170. */
  1171. static void
  1172. w_line_insert (char * buffer, int count)
  1173. {
  1174.     /* Beep and return if the line buffer does not exists. */
  1175.     if (w_wBuf == NULL || w_wCount == NULL) {
  1176.         SysBeep(5);
  1177.         return;
  1178.     }
  1179.  
  1180.     /* Move to the next line, slot and index */
  1181.     w_wLines++;
  1182.     w_wSlot++;
  1183.     w_wIndex += MAX_LINE_CHARS;
  1184.     if (w_wSlot >= MAX_SLOTS) {
  1185.         w_wSlot = 0;
  1186.         w_wIndex = 0;
  1187.     }
  1188.  
  1189.     /* Omit a trailing '\r' */
  1190.     if (count < MAX_LINE_CHARS && buffer[count-1] == '\r') {
  1191.         count--;
  1192.     }
  1193.  
  1194.     /* Silently truncate long lines. */
  1195.     if (count >= MAX_LINE_CHARS-1) {
  1196.         count = MAX_LINE_CHARS-2;
  1197.     }
  1198.  
  1199.     /* Remember the size of the line. */
  1200.     w_wCount[w_wSlot] = count;
  1201.  
  1202.     /* Copy the line to the buffer, deleting the oldest line. */
  1203.     {
  1204.         int i = 0;
  1205.         int j = w_wIndex;
  1206.         for (i = 0; i < count; i++) {
  1207.             w_wBuf[j++] = buffer[i];
  1208.         }
  1209.         w_wBuf[j] = '\0';
  1210.     }
  1211.  
  1212. }
  1213.  
  1214. /*    w_line_out: output one line.
  1215.  
  1216.     This routine works properly even if part of the
  1217.     log window is hidden by another window.
  1218. */
  1219. static void
  1220. w_line_out(void)
  1221. {
  1222.     if (w_activeFlag) {
  1223.         /* Draw a single line. */
  1224.         if (w_wLines > w_wMaxLines  || w_wLines > MAX_SLOTS) {
  1225.             w_scrollWindow();
  1226.         }
  1227.         else {
  1228.             w_curRow += w_dy;
  1229.         }
  1230.  
  1231.         /* Draw one line. */
  1232.         MoveTo(LEFT_OFFSET, w_curRow);
  1233.         DrawText(w_wBuf, w_wIndex, w_wCount[w_wSlot]);
  1234.     }
  1235.     else {
  1236.         /*    Redraw the whole screen.
  1237.             When the log window is inactive scrolling can't be used because
  1238.             ScrollRect only scrolls the visible region.
  1239.  
  1240.             Calling w_line_update instead of ScrollRect creates a
  1241.             flickering screen but I know of no way to avoid this
  1242.             problem.
  1243.         */
  1244.         EraseRect(&w_wp -> portRect);
  1245.         w_line_update();
  1246.     }
  1247. }
  1248.  
  1249. /*    w_line_update: draw every line that should appear in the window. */
  1250. #ifndef min
  1251.     #define min(a,b) (((a) < (b)) ? (a) : (b))
  1252. #endif
  1253.  
  1254. static void
  1255. w_line_update (void)
  1256. {
  1257.     register int limit = 0;
  1258.     register int slot = 0;
  1259.     register int index = 0;
  1260.  
  1261.     /* Return if no lines are in the window. */
  1262.     limit = min(w_wLines, MAX_SLOTS);
  1263.     limit = min(limit, w_wMaxLines);
  1264.     if (limit <= 0) {
  1265.         return;
  1266.     }
  1267.  
  1268.     /*    Redraw as many previous lines as will fit.
  1269.         w_wLines <= limit so slot will be >= 0.
  1270.     */
  1271.     slot = ((w_wLines - limit) % MAX_SLOTS);
  1272.     index = slot * MAX_LINE_CHARS;
  1273.  
  1274.     /*
  1275.         This routine must set w_curRow exactly like w_line_out does.
  1276.         This means that w_curRow is incremented *before* calling DrawText
  1277.         and the initial value must take this into account.
  1278.     */
  1279.     w_curRow = w_y0 - w_dy;
  1280.     {
  1281.         register int i;
  1282.         for (i = 0; i < limit; i++) {
  1283.     
  1284.             /* Draw the text and set the new insertion point. */
  1285.             w_curRow += w_dy;
  1286.             MoveTo(LEFT_OFFSET, w_curRow);
  1287.             DrawText(w_wBuf, index, w_wCount[slot]);
  1288.     
  1289.             /* Move to the next slot. */
  1290.             slot++;
  1291.             index += MAX_LINE_CHARS;
  1292.             if (slot >= MAX_SLOTS) {
  1293.                 slot = 0;
  1294.                 index = 0;
  1295.             }
  1296.         }
  1297.     }
  1298.  
  1299. }
  1300.  
  1301. /*    w_mac_init: an explicit entry point. Initialize the Toolbox and log window.
  1302.  
  1303.     We will eventually crash if toolBoxFlag is set incorrectly.
  1304.     However, toolBoxFlag allows us to detect other kinds of
  1305.     initialization problems.  In particular, w_init will beep rather
  1306.     than crash if it is called before w_mac_init.
  1307. */
  1308. void
  1309. w_mac_init
  1310.     (
  1311.         /* Parameters used to set global variables of the class. */
  1312.         Boolean toolBoxFlag,            Boolean toWindowFlag,
  1313.         char *  windowName,             Boolean openWindowFlag,
  1314.         Boolean addStdMenuFlag,            Boolean addSlMenuFlag,
  1315.         Boolean addAboutFlag,            pstring  aboutTitle,
  1316.         void (*aboutCallBack)(void),    Boolean menuBarFlag,
  1317.         void (*eventCallBack)(void),
  1318.         void (*dumpCallBack)(void),        pstring userItem1,
  1319.         void (*dump2CallBack)(void),    pstring userItem2,
  1320.         void (*dump3CallBack)(void),    pstring userItem3
  1321.     )
  1322. {
  1323.     GrafPtr oldPort;
  1324.  
  1325.     /* Set global variables using the parameters. */
  1326.     w_windowFlag    = toWindowFlag;
  1327.     w_aboutFlag     = addAboutFlag;
  1328.     w_aboutTitle     = aboutTitle;
  1329.     w_stdMenuFlag   = addStdMenuFlag;
  1330.     w_slMenuFlag    = addSlMenuFlag;
  1331.     w_aboutCallBack = aboutCallBack;
  1332.     w_eventCallBack = eventCallBack;
  1333.     w_dumpCallBack     = dumpCallBack;
  1334.     w_userItem1     = userItem1;
  1335.     w_dump2CallBack = dump2CallBack;
  1336.     w_userItem2     = userItem2;
  1337.     w_dump3CallBack = dump3CallBack;
  1338.     w_userItem3     = userItem3;
  1339.  
  1340.     /* Initialize the Macintosh toolbox. */
  1341.     if (toolBoxFlag) {
  1342.         /* Initialize the ToolBox routines. */
  1343.         InitGraf( (Ptr) &(qd.thePort));
  1344.         InitFonts();
  1345.         FlushEvents(everyEvent,0);
  1346.         InitWindows();
  1347.         InitMenus();
  1348.         TEInit();
  1349.         InitDialogs(0L);
  1350.         InitCursor();
  1351.     }
  1352.  
  1353.     GetPort(&oldPort);
  1354.  
  1355.     /* Initialize the window using w_init.
  1356.         Trust the user to have inited the toolbox if toolBoxFlag was FALSE.
  1357.         We will crash in w_init if the application tells a lie here.
  1358.     */
  1359.     w_toolBoxFlag = TRUE;
  1360.     w_init(openWindowFlag, windowName);
  1361.  
  1362.     /* Add any requested menus. */
  1363.     if (!addSlMenuFlag && !addStdMenuFlag) {
  1364.         /* Disable further attempts to add menus. */
  1365.         w_MBarFlag = TRUE;
  1366.     }
  1367.     else if (menuBarFlag) {
  1368.         w_drawMenuBar();
  1369.     }
  1370.  
  1371.     SetPort(oldPort);
  1372. }
  1373.  
  1374. /*    w_menuSelect: a hidden entry point called by the MenuSelect macro.
  1375.  
  1376.     Call the MenuSelect() Toolbox routine.
  1377. */
  1378. long
  1379. w_menuSelect(Point pt)
  1380. {
  1381.     GrafPtr oldPort;
  1382.     long val = 0;
  1383.  
  1384.     GetPort(&oldPort);
  1385.  
  1386.     /* Initialize the log window if required. */
  1387.     if (!w_wInitFlag) {
  1388.         w_init(FALSE, "log");
  1389.     }
  1390.  
  1391.     SetPort(w_wp);
  1392.  
  1393.     /* Update the menu bar. */
  1394.     if (w_MBarFlag && w_slMenuFlag) {
  1395.  
  1396.         if (log_isopen()) {
  1397.             SetItem(w_menuH, W_FILE_ITEM, "\pClose File");
  1398.         }
  1399.         else {
  1400.             SetItem(w_menuH, W_FILE_ITEM, "\pOpen File");
  1401.         }
  1402.  
  1403.         if (w_showFlag) {
  1404.             SetItem(w_menuH, W_WINDOW_ITEM, "\pClose Window");
  1405.         }
  1406.         else {
  1407.             SetItem(w_menuH, W_WINDOW_ITEM, "\pOpen Window");
  1408.         }
  1409.     }
  1410.  
  1411.     /* Call the Toolbox version of Menuselect and set val. */
  1412.     val = MenuSelect(pt);
  1413.     if (w_command(val)) {
  1414.         val = 0;
  1415.     }
  1416.         
  1417.     SetPort(oldPort);
  1418.     return val;
  1419. }
  1420.  
  1421. /*    w_pStr: print a pascal string. */
  1422. static void
  1423. w_pStr(char * s)
  1424. {
  1425.     int i = *s++;
  1426.     while (i--) {
  1427.         echar(*s);
  1428.         s++;
  1429.     }
  1430. }
  1431.  
  1432. /*    w_rawDialog: get the Sherlock arguments into w_comBuf.
  1433.  
  1434.     Set w_windowFlag as appropriate.
  1435.     Return TRUE if a file has been requested to be opened.
  1436.  
  1437.     Do not put any Sherlock macros into this routine.
  1438. */
  1439.  
  1440. #define b (qd.screenBits.bounds)
  1441.  
  1442. #define W_ABORT_RAW_DIALOG    7
  1443.  
  1444. static Boolean
  1445. w_rawDialog(
  1446.     short * vRefNum, char * fileName, int max_fileName,
  1447.     char * fileNamePrompt, char * defaultFileName)
  1448. {
  1449.     DialogPtr    dp;
  1450.     GrafPtr        oldPort;
  1451.     Rect        tempRect;
  1452.     short        DType;
  1453.     Handle        DItem;
  1454.     Boolean        fileFlag = FALSE;
  1455.  
  1456.     GetPort(&oldPort);
  1457.  
  1458.     /* Create the dialog window. */
  1459.     dp = GetNewDialog(SHERLOCK_DIALOG_ID, NULL, (WindowPtr)-1);
  1460.     if (dp == 0L) {
  1461.         w_abort(W_ABORT_RAW_DIALOG);
  1462.     }
  1463.  
  1464.     /* Set tempRect to the portRect set by GetNewDialog. */
  1465.     tempRect.top    = dp -> portRect.top;
  1466.     tempRect.left   = dp -> portRect.left;
  1467.     tempRect.bottom = dp -> portRect.bottom;
  1468.     tempRect.right  = dp -> portRect.right;
  1469.  
  1470.     tempRect.top = ((b.bottom-b.top) - (tempRect.bottom-tempRect.top)) / 2;
  1471.     tempRect.left    = ((b.right-b.left) - (tempRect.right-tempRect.left)) / 2;
  1472.  
  1473.     /* Draw the dialog window. */
  1474.     MoveWindow(dp, tempRect.left, tempRect.top, TRUE);
  1475.     ShowWindow(dp);
  1476.     SelectWindow(dp);
  1477.     SetPort(dp);
  1478.  
  1479.     /* Set the characteristics of the text. */
  1480.     {
  1481.         TEHandle d_TEH = ((DialogPeek) dp) -> textH;
  1482.         HLock( (Handle) d_TEH);
  1483.             (*d_TEH) -> txSize = 12;
  1484.             TextSize(12);
  1485.             (*d_TEH) -> txFont = systemFont;
  1486.             TextFont(systemFont);
  1487.             (*d_TEH) -> fontAscent = 12;
  1488.             (*d_TEH) -> lineHeight = 12 + 3 + 1;
  1489.         HUnlock( (Handle) d_TEH);
  1490.     }
  1491.  
  1492.     /*    Initialize the dialog. */
  1493.     GetDItem(dp,SHERLOCK_ARGS_ITEM, &DType, &DItem, &tempRect);
  1494.     SetIText(DItem, "\p");
  1495.     w_hiliteButton(dp);
  1496.  
  1497.     /* Handle all dialog events. */
  1498.     for(;;) {
  1499.     
  1500.         short itemHit;
  1501.  
  1502.         /* Get the next dialog event. */
  1503.         ModalDialog(NULL, &itemHit);
  1504.         GetDItem(dp, itemHit, &DType, &DItem, &tempRect);
  1505.  
  1506.         if (itemHit == OK_ITEM ) {
  1507.             /* Handle it real time */
  1508.             break;
  1509.         }
  1510.  
  1511.         if (itemHit == CANCEL_ITEM) {
  1512.             /* Restore the default settings. */
  1513.             fileFlag = FALSE;
  1514.             break;
  1515.         }
  1516.  
  1517.         if (itemHit == TO_DISK_FILE_ITEM ) {
  1518.             fileFlag = !fileFlag;
  1519.             SetCtlValue( ((ControlHandle) DItem), fileFlag);
  1520.             if (fileFlag) {
  1521.                 fileFlag = w_std_file_dialog(vRefNum, fileName, max_fileName,
  1522.                     fileNamePrompt, defaultFileName);
  1523.                 SetCtlValue( ((ControlHandle) DItem), fileFlag);
  1524.                 w_hiliteButton(dp);
  1525.  
  1526.                 /* 12/6/90 */
  1527.                 slw_update();
  1528.             }
  1529.         }
  1530.  
  1531.     }
  1532.  
  1533.     /* Get the arguments into w_comBuf */
  1534.     GetDItem(dp,SHERLOCK_ARGS_ITEM, &DType, &DItem, &tempRect);
  1535.     GetIText(DItem, &w_comBuf[0]);
  1536.     PtoCstr((pstring) &w_comBuf[0]);
  1537.  
  1538.     /* Dismiss the dialog box. */
  1539.     DisposDialog(dp);
  1540.  
  1541.     SetPort(oldPort);
  1542.  
  1543.     slw_update();
  1544.  
  1545.     return fileFlag;
  1546. }
  1547.  
  1548. #undef b
  1549.  
  1550. /*    w_scrollWindow: scroll the log window by calling ScrollRect.
  1551.  
  1552.     ScrollRect will not work properly if the log window is covered
  1553.     since its visRgn will not include the whole window.
  1554. */
  1555.  
  1556. static void
  1557. w_scrollWindow(void)
  1558. {
  1559.     RgnHandle rH = NewRgn();
  1560.     ScrollRect(&w_clipRect, 0, -w_dy, rH);
  1561.     DisposeRgn(rH);
  1562. }
  1563.  
  1564. /*    w_setupWindow: Set the globals describing the log window. */
  1565. static void
  1566. w_setupWindow(void)
  1567. {
  1568.     FontInfo info;
  1569.  
  1570.     /* Set w_y0, w_dy, and w_y0 to describe the window's font. */
  1571.     TextFont(4);        /* Specify Monaco 9. */
  1572.     TextSize(9);
  1573.     GetFontInfo(&info);
  1574.     w_height    = info.ascent;
  1575.     w_dy        = info.ascent + info.descent + info.leading + EXTRA_LEADING;
  1576.     w_y0        = w_height + TOP_CLIP;
  1577.  
  1578.     /* Set w_maxRow.  It is used only to set the clipping and scrolling regions. */
  1579.     w_maxRow = (w_wp -> portRect.bottom - w_wp -> portRect.top)
  1580.         - SBarWidth - BOTTOM_CLIP;
  1581.  
  1582.     /* Set w_wMaxLines and w_curRow.
  1583.         The first line of text will be positioned at w_y0.
  1584.         Count 1 for that row plus rows/w_dy.
  1585.         Reserve rows for the descender on the last line.
  1586.     */
  1587.     {
  1588.         int rows = w_maxRow - w_y0 - info.descent;
  1589.         w_wMaxLines = 1 + (rows/w_dy);
  1590.     }
  1591.  
  1592.     /* Allow for pre-increment of w_dy in sl_out_line. */
  1593.     w_curRow = w_y0 - w_dy;
  1594.  
  1595.     /* Set w_clipRect and call ClipRect. */
  1596.     SetRect(&w_clipRect,
  1597.         w_wp -> portRect.left,
  1598.         w_wp -> portRect.top + TOP_CLIP,
  1599.         w_wp -> portRect.right    -SBarWidth - RIGHT_CLIP,
  1600.         w_wp -> portRect.top + w_maxRow);
  1601.  
  1602.     ClipRect(&w_clipRect);
  1603.  
  1604. }
  1605.  
  1606. /*    w_show: show the log window. */
  1607. static void
  1608. w_show(void)
  1609. {
  1610.     ShowWindow(w_wp);
  1611.     w_showFlag = TRUE;
  1612.     slw_update();
  1613. }
  1614.  
  1615. /*    w_std_file_dialog: Get a file name (for write access) into fileName.
  1616.     Get a volume number into vRefNum.
  1617.  
  1618.     Return TRUE if all is well.
  1619. */
  1620. static int
  1621. w_std_file_dialog(
  1622.     short * vRefNum,
  1623.     char * fileName,
  1624.     int max_fileName,
  1625.     char * fileNamePrompt,
  1626.     char * defaultFileName)
  1627. {
  1628.     SFReply    reply;
  1629.     
  1630.     /* Get the file name, using a Standard File Dialog. */
  1631.     CtoPstr(defaultFileName);
  1632.     CtoPstr(fileNamePrompt);
  1633.  
  1634.     {
  1635.         Point    upper_left;
  1636.         upper_left.h = 100;
  1637.         upper_left.v = 50;
  1638.  
  1639.         SFPutFile(
  1640.             upper_left,                    /* Corner of dialog. */
  1641.             (pstring) fileNamePrompt,    /* Prompt string. */
  1642.             (pstring) defaultFileName,    /* Default file name. */
  1643.             NULL,                        /* dlgHook field. */
  1644.             &reply);                    /* reply record. */
  1645.     }
  1646.  
  1647.     PtoCstr((pstring) defaultFileName);
  1648.     PtoCstr((pstring) fileNamePrompt);
  1649.  
  1650.     /* Redraw the screen after the Standard File Dialog has been dismissed. */
  1651.     slw_update();
  1652.  
  1653.     if (reply.good) {
  1654.         /* Set fileName and vRefNum.  Return FALSE if the file name is bad. */
  1655.  
  1656.         /* The maximum length of the file name is 63 characters. */
  1657.         PtoCstr( (pstring) &reply.fName);
  1658.  
  1659.         /* 3/21/91 */
  1660.         if (strlen((char *) &reply.fName) < max_fileName) {
  1661.             strcpy(fileName, (char *) &reply.fName);
  1662.         }
  1663.         else {
  1664.             return FALSE;
  1665.         }
  1666.  
  1667.         /* Check for null file name. */
  1668.         if (fileName[0] == '\0') {
  1669.             return FALSE;
  1670.         }
  1671.  
  1672.         *vRefNum = reply.vRefNum;
  1673.         return TRUE;
  1674.     }
  1675.     else {
  1676.         return FALSE;
  1677.     }
  1678. }
  1679.  
  1680. /*    slw_update: an explicit entry point.
  1681.     Redraw the log window in response to an update event.
  1682. */
  1683. void
  1684. slw_update(void)
  1685. {
  1686.     GrafPtr oldPort;
  1687.     GetPort(&oldPort);
  1688.  
  1689.     /* Initialize the log window if required. */
  1690.     if (!w_wInitFlag) {
  1691.         w_init(FALSE, "log");
  1692.     }
  1693.  
  1694.     /*    Redraw the screen.
  1695.         The advantage of putting as much code as possible between
  1696.         BeginUpdate and EndUpdate is that only those operations on
  1697.         the update region are actually drawn.
  1698.     */
  1699.  
  1700.     SetPort(w_wp);
  1701.     BeginUpdate(w_wp);
  1702.  
  1703.         /* Expand the clipping region. */
  1704.         w_setupWindow();
  1705.         ClipRect(&w_wp->portRect);
  1706.         EraseRect(&w_wp->portRect);
  1707.         DrawGrowIcon(w_wp);
  1708.  
  1709.         /* Contract the clipping region. */
  1710.         w_setupWindow();
  1711.         w_line_update();
  1712.  
  1713.     EndUpdate(w_wp);
  1714.  
  1715.     SetPort(oldPort);
  1716. }
  1717.  
  1718. /*    w_write: an explicit entry point.  Write a line to the window. */
  1719. void
  1720. slw_write(char * buffer, int count)
  1721. {
  1722.     GrafPtr    oldPort;
  1723.     GetPort(&oldPort);
  1724.  
  1725.     /* Open the window so we can be alerted if something happens. */
  1726.     if (!w_wInitFlag) {
  1727.         w_init(TRUE, "log");
  1728.     }
  1729.  
  1730.     SetPort(w_wp);
  1731.  
  1732.     /* Write the line to the window. */
  1733.     if (w_windowFlag) {
  1734.  
  1735.         /* Make the weird Mac conversion from '\n' to '\r' */
  1736.         if (count > 0 && buffer[count-1] == '\n') {
  1737.             buffer[count-1] = '\r';
  1738.         }
  1739.         w_line_insert(buffer, count);
  1740.         w_line_out();
  1741.     }
  1742.  
  1743.     /* Allow a break by invoking the event callback routine. */
  1744.     if (w_eventCallBack != 0L) {
  1745.         (*w_eventCallBack)();
  1746.     }
  1747.  
  1748.     SetPort(oldPort);
  1749. }
  1750.  
  1751. /*    w_zoom: zoom the log window in or out. */
  1752. static void
  1753. w_zoom(Point global_pt, int zoomCode)
  1754. {
  1755.     if(TrackBox(w_wp, global_pt, zoomCode)) {
  1756.  
  1757.         ZoomWindow(w_wp, zoomCode, FALSE);
  1758.  
  1759.         /* Set the clipping region for DrawGrowIcon. */
  1760.         ClipRect(&w_wp->portRect);
  1761.  
  1762.         EraseRect(&w_wp->portRect);
  1763.         DrawGrowIcon(w_wp);
  1764.  
  1765.         w_setupWindow();
  1766.         w_line_update();
  1767.     }
  1768. }
  1769.